package io.lvdaxian.mybatis09.executor;

import io.lvdaxian.mybatis09.mapping.BoundSql;
import io.lvdaxian.mybatis09.mapping.MappedStatement;
import io.lvdaxian.mybatis09.session.Configuration;
import io.lvdaxian.mybatis09.session.ResultHandler;
import io.lvdaxian.mybatis09.transaction.Transaction;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.List;

/**
 * 执行器 公共的方法都是这里维护
 *
 * @author lihh
 */
public abstract class BaseExecutor implements Executor {
  private final org.slf4j.Logger logger = LoggerFactory.getLogger(BaseExecutor.class);
  
  // 配置类 其实会发现配置类 贯穿整个上下文
  protected Configuration configuration;
  // 事务
  protected Transaction transaction;
  // 执行器
  protected Executor wrapper;
  
  @Override
  public Transaction getTransaction() {
    if (closed)
      throw new RuntimeException("Executor was closed.");
    return transaction;
  }
  
  @Override
  public void rollback(boolean required) throws SQLException {
    if (!closed)
      if (required)
        transaction.rollback();
  }
  
  
  @Override
  public void close(boolean forceRollback) {
    try {
      if (!closed)
        if (forceRollback)
          transaction.close();
    } catch (Exception e) {
      logger.warn("Unexpected exception on closing transaction.  Cause: {}", e);
      
    } finally {
      transaction = null;
      closed = true;
    }
  }
  
  // 是否关闭
  private boolean closed;
  
  public BaseExecutor(Configuration configuration, Transaction transaction) {
    this.configuration = configuration;
    this.transaction = transaction;
    this.wrapper = this;
  }
  
  
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
    if (closed)
      throw new RuntimeException("Executor was closed.");
    
    return doQuery(ms, parameter, resultHandler, boundSql);
  }
  
  /**
   * 该方法由 各自的继承者来实现
   *
   * @param ms            statement 语句
   * @param parameter     参数
   * @param resultHandler 结果handler
   * @param boundSql      待执行sql
   * @param <E>           动态参数
   * @return 返回集合
   * @author lihh
   */
  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql);
  
  @Override
  public void commit(boolean required) throws SQLException {
    if (closed)
      throw new RuntimeException("Cannot commit, transaction is already closed");
    if (required)
      transaction.commit();
  }
}
